#include <stdio.h>
#include <stdlib.h>
#include <libudev.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <linux/input.h>
#include <fcntl.h>

// 检查设备是否支持指定的事件类型和事件码
int check_event_support(int fd, unsigned int event_type, unsigned int event_code) {
    unsigned char evbit[EV_MAX / 8 + 1] = {0};
    unsigned char keybit[KEY_MAX / 8 + 1] = {0};

    if (ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), evbit) < 0) {
        return 0;
    }

    if (!(evbit[event_type / 8] & (1 << (event_type % 8)))) {
        return 0;
    }

    if (ioctl(fd, EVIOCGBIT(event_type, sizeof(keybit)), keybit) < 0) {
        return 0;
    }

    if (!(keybit[event_code / 8] & (1 << (event_code % 8)))) {
        return 0;
    }

    return 1;
}

// 判断设备是否为鼠标
int is_mouse(const char *devnode) {
    int fd = open(devnode, O_RDONLY | O_NONBLOCK);
    if (fd < 0) {
        return 0;
    }

    int has_left_button = check_event_support(fd, EV_KEY, BTN_LEFT);
    int has_relative_movement_x = check_event_support(fd, EV_REL, REL_X);
    int has_relative_movement_y = check_event_support(fd, EV_REL, REL_Y);

    close(fd);

    return has_left_button && (has_relative_movement_x || has_relative_movement_y);
}

static char mouse_name[64];
// 定义鼠标插入和拔出事件处理函数
void *handle_mouse_events(void *arg) 
{
    struct udev *udev;
    struct udev_monitor *mon;
    int fd;

    // 初始化 udev 上下文
    udev = udev_new();
    if (!udev) {
        perror("Failed to create udev context");
        return NULL;
    }

    // 创建一个 udev 监控器，监听输入子系统的设备事件
    mon = udev_monitor_new_from_netlink(udev, "udev");
    if (!mon) {
        perror("Failed to create udev monitor");
        udev_unref(udev);
        return NULL;
    }

    // 过滤输入子系统的设备事件
    udev_monitor_filter_add_match_subsystem_devtype(mon, "input", NULL);
    udev_monitor_enable_receiving(mon);

    // 获取监控器的文件描述符
    fd = udev_monitor_get_fd(mon);

    printf("Monitoring for mouse insertion and removal events...\n");

    while (1) {
        fd_set fds;
        struct timeval tv;
        int ret;

        FD_ZERO(&fds);
        FD_SET(fd, &fds);
        tv.tv_sec = 0;
        tv.tv_usec = 0;

        // 使用 select 函数监听文件描述符
        ret = select(fd + 1, &fds, NULL, NULL, &tv);
        if (ret > 0 && FD_ISSET(fd, &fds)) {
            // 接收设备事件
            struct udev_device *dev = udev_monitor_receive_device(mon);
            if (dev) {
                const char *action = udev_device_get_action(dev);
                const char *devnode = udev_device_get_devnode(dev);

                if (devnode) 
                {
                    if (strcmp(action, "add") == 0 && is_mouse(devnode)) {
                        memcpy (mouse_name, devnode, strlen(devnode));
                        printf("Mouse inserted: %s\n", devnode);
                    } 
                    if (strcmp(action, "remove") == 0 && strstr(mouse_name, devnode)) 
                    {
                        printf("Mouse removed: %s\n", devnode);
                    }
                }
                // 释放设备对象
                udev_device_unref(dev);
            }
        }
    }

    // 释放资源
    udev_monitor_unref(mon);
    udev_unref(udev);
    return NULL;
}


int main() {
    pthread_t mouse_event_pth_id;
    pthread_create (&mouse_event_pth_id, NULL, handle_mouse_events, NULL);
    while (1){
        sleep(1);
    }
    return 0;
}